﻿#include <stdarg.h>
#include "Logger.h"

fast_io::u8obuf_file_mutex Logger::log_file{};
bool Logger::can_refresh = false;

void Logger::Enable() noexcept {
	// init region time
	fast_io::posix_tzset();  
	// dir_file
	fast_io::dir_file df(fast_io::u8concat(Utils::Utils::RoamingStateFold, u8"Logs\\"));
	// copy old log
	try {
		fast_io::u8ibuf_file log(at(df), fast_io::u8concat(Utils::Utils::ClientName, u8".log"), fast_io::open_mode::text);
		fast_io::u8obuf_file oldlog(at(df), fast_io::u8concat(Utils::Utils::ClientName, u8" Last Log.log"), fast_io::open_mode::text);
		fast_io::transmit(oldlog, log);
	} catch (const fast_io::error &) {
	}
	// new log
	log_file.reopen(at(df), fast_io::u8concat(Utils::Utils::ClientName, u8".log"), fast_io::open_mode::text);
}

void Logger::Log(LogGrade grade, const std::u8string_view sv) noexcept {

	println(log_file, fast_io::mnp::left(local(fast_io::posix_clock_gettime(fast_io::posix_clock_id::realtime)), 34), GetGradeName(grade), sv);
	can_refresh = true;
}

void Logger::LogF(LogGrade grade, const char8_t *args, ...) {

	va_list arg_val;
	va_start(arg_val, args);

	auto lengthNeeded = _vscprintf((char *)args, arg_val) + 1;
	char8_t *message = new char8_t[lengthNeeded];
	vsprintf_s((char *)message, lengthNeeded, (char *)args, arg_val);
	Log(grade, std::u8string_view{message, static_cast<size_t>(lengthNeeded - 1)});
	delete[] message;

	va_end(arg_val);
}

void Logger::Disable() noexcept {
	log_file.close();
}

void Logger::Refresh() noexcept {
	if (can_refresh) {  // has Log
		can_refresh = false;
		//log_file.reopen(log_file_name, fast_io::open_mode::text | fast_io::open_mode::app);
		flush(log_file);
	}
}

#ifdef _DEBUG
#include <stacktrace>

void Logger::ShowTraceStack() noexcept {
	auto trace = std::stacktrace::current();
	std::string temp = std::to_string(trace);
	LogC(LogGrade::info, fast_io::mnp::chvw(u8'\n'), *reinterpret_cast<std::u8string*>(&temp));
}


#ifdef HELIUM_USE_SIGNUM
void Logger::AbortSignal(int signum) noexcept {
	LogC(LogGrade::fatal, u8"Helium Crash! Crash Code: ", signum);
	ShowTraceStack();
	Disable();

	// Clean Memory....
}
#else
void Logger::AbortSignal() noexcept {
	LogC(LogGrade::fatal, u8"Helium Crash!");
	ShowTraceStack();
	Disable();

	// Clean Memory....
}
#endif  // 0
#endif
